// 文件路径: src/main/java/org/csu/mybigpro/service/IflytekClient.java

package org.csu.mybigpro.service;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class IflytekClient extends WebSocketClient {

    private static final Logger logger = LoggerFactory.getLogger(IflytekClient.class);
    private static final Gson gson = new Gson();

    private final String appId;
    private final Consumer<String> onResultCallback;

    // ======================= 【核心修改 1】 =======================
    // 用于拼接当前这句话的识别结果
    private final StringBuilder currentResultBuilder = new StringBuilder();
    // ==========================================================

    private IflytekClient(URI serverUri, String appId, Consumer<String> onResult) {
        super(serverUri);
        this.appId = appId;
        this.onResultCallback = onResult;
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        logger.info("成功连接到讯飞服务器。 Status: {}", handshakedata.getHttpStatusMessage());
        sendStartFrame();
    }

    @Override
    public void onMessage(String message) {
        ResponseMessage resp = gson.fromJson(message, ResponseMessage.class);
        if (resp != null) {
            if (resp.getCode() != 0) {
                logger.error("讯飞返回错误: code={}, message={}", resp.getCode(), resp.getMessage());
                this.close();
                return;
            }
            if (resp.getData() != null) {
                // ======================= 【核心修改 2】 =======================
                // 重写消息处理逻辑，以拼接结果
                String partialResult = resp.getData().getResultText();
                if (partialResult != null) {
                    currentResultBuilder.append(partialResult);
                }

                // status 为 2 表示这是最后一句话的最终结果
                if (resp.getData().getStatus() == 2) {
                    String finalSentence = currentResultBuilder.toString();
                    onResultCallback.accept(finalSentence);

                    // 重置拼接器，并关闭连接，为下一句话做准备
                    currentResultBuilder.setLength(0);
                    this.close();
                }
                // ==========================================================
            }
        }
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        logger.info("与讯飞服务器的连接已关闭。 Code: {}, Reason: {}", code, reason);
    }

    @Override
    public void onError(Exception ex) {
        logger.error("与讯飞服务器的连接发生错误。", ex);
    }

    private void sendStartFrame() {
        JsonObject frame = new JsonObject();

        JsonObject common = new JsonObject();
        common.addProperty("app_id", this.appId);
        frame.add("common", common);

        JsonObject business = new JsonObject();
        business.addProperty("language", "zh_cn");
        business.addProperty("domain", "iat");
        business.addProperty("accent", "mandarin");
        business.addProperty("vad_eos", 5000);
        // 新增参数 ptt=0，让讯飞不自动加标点，我们最后在客户端根据需要添加
        business.addProperty("ptt", 0);
        frame.add("business", business);

        JsonObject data = new JsonObject();
        data.addProperty("status", 0);
        data.addProperty("format", "audio/L16;rate=16000");
        data.addProperty("encoding", "raw");
        frame.add("data", data);

        this.send(frame.toString());
    }

    public void sendAudio(byte[] audioData) {
        if (this.isOpen()) {
            JsonObject frame = new JsonObject();
            JsonObject data = new JsonObject();
            data.addProperty("status", 1);
            data.addProperty("format", "audio/L16;rate=16000");
            data.addProperty("encoding", "raw");
            data.addProperty("audio", Base64.getEncoder().encodeToString(audioData));
            frame.add("data", data);
            this.send(frame.toString());
        }
    }

    public void sendEnd() {
        if (this.isOpen()) {
            JsonObject frame = new JsonObject();
            JsonObject data = new JsonObject();
            data.addProperty("status", 2);
            frame.add("data", data);
            this.send(frame.toString());
            logger.info("已发送结束帧到讯飞。");
        }
    }

    static class ResponseMessage {
        private int code;
        private String message;
        private ResponseData data;
        public int getCode() { return code; }
        public String getMessage() { return message; }
        public ResponseData getData() { return data; }
    }

    static class ResponseData {
        private int status;
        private ResponseResult result;
        public int getStatus() { return status; }
        public String getResultText() {
            if (result == null || result.ws == null) {
                return null;
            }
            StringBuilder resultBuilder = new StringBuilder();
            for (ResponseWord word : result.ws) {
                if (word.cw != null) {
                    for (Cw character : word.cw) {
                        if (character.w != null) {
                            resultBuilder.append(character.w);
                        }
                    }
                }
            }
            return resultBuilder.toString();
        }
    }

    static class ResponseResult { List<ResponseWord> ws; }
    static class ResponseWord { List<Cw> cw; }
    static class Cw { String w; }

    @Component
    public static class IflytekClientFactory {
        @Value("${iflytek.api.appid}")
        private String appId;
        @Value("${iflytek.api.key}")
        private String apiKey;
        @Value("${iflytek.api.secret}")
        private String apiSecret;
        private static final String HOST = "iat-api.xfyun.cn";
        private static final String API_PATH = "/v2/iat";

        public IflytekClient create(Consumer<String> onResult) throws Exception {
            String authUrl = getAuthUrl();
            URI uri = new URI(authUrl.replace("https://", "wss://"));
            IflytekClient client = new IflytekClient(uri, appId, onResult);
            client.connect();
            return client;
        }

        private String getAuthUrl() throws Exception {
            URL url = new URL("https://" + HOST + API_PATH);
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());

            String builder = "host: " + HOST + "\n" +
                    "date: " + date + "\n" +
                    "GET " + API_PATH + " HTTP/1.1";

            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.getBytes(StandardCharsets.UTF_8));
            String sha = Base64.getEncoder().encodeToString(hexDigits);

            String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                    apiKey, "hmac-sha256", "host date request-line", sha);

            return url.toString() + "?" + "authorization=" + Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))
                    + "&" + "date=" + date.replace(" ", "%20")
                    + "&" + "host=" + HOST;
        }
    }
}